package com.lisen.codegenerator.util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 代码生成器入口
 * 
 * @author lisen
 * 
 */
public class CodeGenerator {
	static final String BASE_CONFIG = "com/lisen/codegenerator/util/config/cg-config.xml";
	private static SAXReader saxReader;
	private static String outPath;
	private static String baseTemplatePath;
	private static String dirRoot;
	private static String encoding = "UTF-8";
	private static String replaceNameStr = "Template";
	private static List<String> fileList = new ArrayList<String>();

	static void init() throws Exception {
		saxReader = new SAXReader();
		consolePrint("解析器创建成功");
		Properties properties = new Properties();
		// 将当前路径设置到VelocityEngine 中
		properties.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH,
				CodeGenerator.class.getClassLoader().getResource("").getFile());
		properties.setProperty(Velocity.ENCODING_DEFAULT, encoding);
		properties.setProperty(Velocity.INPUT_ENCODING, encoding);
		properties.setProperty(Velocity.OUTPUT_ENCODING, encoding);
		Velocity.init(properties);
		consolePrint("Velocity初始化成功");
	}

	private static void mkdirs(String filedir) {
		File f = new File(filedir);
		if (!f.exists()) {
			f.mkdirs();
		}
	}

	private static void mknewdirs(String filedir) {
		File f = new File(filedir);
		if (f.exists()) {
			f.delete();
		}
		f.mkdirs();
	}

	private static String filePathHandle(String path) {
		return path.replaceAll("\\\\", "/");
	}

	private static void fileAdd(VelocityContext context, String file)
			throws Exception {
		consolePrint("-----------");
		file = filePathHandle(file);
		int startSub = file.indexOf(baseTemplatePath)
				+ baseTemplatePath.length();
		int endSub = file.lastIndexOf("/");
		// 相对文件夹
		String dir = file.substring(startSub, endSub);
		String sheetname = ((ClassDescriptorImporter) context.get("list"))
				.getSheetname();
		String fileName = file.substring(endSub, file.lastIndexOf("."))
				.replace(replaceNameStr,
						GeneratorUtility.firstToUpperCase(sheetname));
		consolePrint("读取模版文件:" + file);
		Template template = Velocity.getTemplate(templatePath(file));
		// 创建输出文件夹
		String realOutPath = dirRoot + dir;
		mkdirs(realOutPath);
		String outFilePath = realOutPath + fileName;
		// 加载vm模板
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
				new FileOutputStream(outFilePath), encoding));
		template.merge(context, writer);
		writer.flush();
		writer.close();
		consolePrint("生成文件:" + outFilePath);
		fileList.add(file);
		consolePrint("-----------");
	}

	private static String templatePath(String file) {
		String base = CodeGenerator.class.getResource("/").getFile().substring(
				1);
		return file.substring(base.length(), file.length());
	}

	/**
	 * 
	 * @param path
	 *            文件路径
	 * @param suffix
	 *            后缀名
	 * @param isdepth
	 *            是否遍历子目录
	 * @return
	 */
	private static List getListFiles(VelocityContext context, String path,
			String suffix, boolean isdepth) throws Exception {
		File file = new File(path);
		return listFile(context, file, suffix, isdepth);
	}

	private static List listFile(VelocityContext context, File f,
			String suffix, boolean isdepth) throws Exception {
		// 是目录，同时需要遍历子目录
		if (f.isDirectory() && isdepth == true) {
			File[] t = f.listFiles();
			for (int i = 0; i < t.length; i++) {
				listFile(context, t[i], suffix, isdepth);
			}
		} else {
			String filePath = f.getPath();// .getAbsolutePath();
			if (suffix == "" || suffix == null) {
				// 后缀名为null则为所有文件
				fileAdd(context, filePath);
			} else {
				int begIndex = filePath.lastIndexOf(".");// 最后一个.(即后缀名前面的.)的索引
				String tempsuffix = "";
				// 防止是文件但却没有后缀名结束的文件
				if (begIndex != -1) {
					tempsuffix = filePath.substring(begIndex + 1, filePath
							.length());
				}

				if (tempsuffix.equals(suffix)) {
					fileAdd(context, filePath);
				}
			}
		}
		return fileList;
	}

	private static void start(String modelFile) throws Exception {
		Document document = saxReader.read(new File(modelFile));
		ClassDescriptorImporter cdi = new ClassDescriptorImporter();
		cdi.parse(document);
		consolePrint("配置信息解析成功");
		// 创建存放文件夹
		dirRoot = outPath + "/" + "ws_" + cdi.getSheetname() + "/";

		// 上下文信息
		VelocityContext context = new VelocityContext();
		context.put("list", cdi);
		context.put("util", GeneratorUtility.getInstance());
		List arrayList = getListFiles(context, CodeGenerator.class.getResource(
				"/").getFile()
				+ baseTemplatePath, "vm", true);
	}

	public static void main(String args[]) throws Exception {
		consolePrint("程序启动");
		CodeGenerator.init();
		Document document = saxReader.read(new File(configPath()));
		consolePrint("获取配置文件成功");
		Iterator templateFiles = document.getRootElement().elementIterator(
				"template");
		while (templateFiles.hasNext()) {
			Element file = (Element) templateFiles.next();
			String basePath = filePathHandle(file
					.attributeValue("baseConfigPath"));
			consolePrint("模版配置文件基路径：" + basePath);
			baseTemplatePath = filePathHandle(file
					.attributeValue("baseTemplatePath"));
			consolePrint("模版文件基路径：" + baseTemplatePath);
			outPath = file.attributeValue("outPath");
			// 建立新的输出文件夹
			mknewdirs(outPath);
			consolePrint("输出路径：" + outPath);
			Iterator files = file.elementIterator("file");
			while (files.hasNext()) {
				Element fe = (Element) files.next();
				consolePrint("====================");
				consolePrint("加载模板文件开始生成:" + fe.getTextTrim());
				CodeGenerator.start(CodeGenerator.class.getClassLoader()
						.getResource(basePath + fe.getText()).getFile());
				consolePrint("文件处理完成:" + fe.getTextTrim());
				consolePrint("");
			}
			break;
		}
		consolePrint("程序完成");
	}

	private static String configPath() {
		// return CodeGenerator.class.getResource("/").getPath() + BASE_CONFIG;
		return filePathHandle(CodeGenerator.class.getClassLoader().getResource(
				BASE_CONFIG).getFile());
	}

	public static void consolePrint(String message) {
		System.out.println(new StringBuilder("^_^【").append(new Date()).append(
				"】").append(message).toString());
	}
}
